package net.csdn.business.notify.handler.flowcontrol;

import lombok.extern.slf4j.Slf4j;
import net.csdn.business.notify.common.enums.NotifyChannel;
import net.csdn.business.notify.common.enums.RateLimitStrategy;
import net.csdn.business.notify.common.pipeline.domain.TaskInfo;
import net.csdn.business.notify.handler.flowcontrol.annotations.LocalRateLimit;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;



/**
 * @ClassName FlowControlFactory
 * @Description 限流工厂类
 * @Author zhangyl
 * @Date 2023/11/30 17:38
 */
@Service
@Slf4j
public class FlowControlFactory implements ApplicationContextAware {

    private final Map<RateLimitStrategy, FlowControlService> flowControlServiceMap = new ConcurrentHashMap<>();

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public void flowControl(TaskInfo taskInfo, FlowControlParam flowControlParam) {
        FlowControlService flowControlService = flowControlServiceMap.get(flowControlParam.getRateLimitStrategy());
        if (Objects.isNull(flowControlService)) {
            log.error("没有找到对应的单机限流策略");
            return;
        }
        double costTime = flowControlService.flowControl(taskInfo, flowControlParam);
        if (costTime > 0) {
            log.info("notify channel: {} flow control time {}", NotifyChannel.getChannelType(taskInfo.getNotifyChannel()).getDescription(), costTime);
        }
    }


    @PostConstruct
    private void init() {
        Map<String, Object> serviceMap = this.applicationContext.getBeansWithAnnotation(LocalRateLimit.class);
        serviceMap.forEach((name, service) -> {
            if (service instanceof FlowControlService) {
                LocalRateLimit localRateLimit = AopUtils.getTargetClass(service).getAnnotation(LocalRateLimit.class);
                RateLimitStrategy rateLimitStrategy = localRateLimit.rateLimitStrategy();
                //通常情况下 实现的限流service与rateLimitStrategy一一对应
                flowControlServiceMap.put(rateLimitStrategy, (FlowControlService) service);
            }
        });
    }
}
